#include "masking.h"
#include "symbol.h"
#include "stringutils.h"

#include <cmath>

#include <QDebug>

namespace qrcode {

const int Masking::DIR_ROW = 1;
const int Masking::DIR_COL = 0;


Masking::Masking(int version)
    :version(version)
{
    nMods = 21 + 4*(version-1);
}

void Masking::MakeMasking()
{
    //1.生成掩摸图形
    //std::vector<QImage> maskImgs = MaskPatterns();

    //2.生成待评估结果
    std::vector<QImage> resultImgs = MaskedImg();
    QImage img;
    for(int i = 0; i < resultImgs.size(); i++){
        img = resultImgs.at(i);
        img.save(QString("/home/daowm/Workspace/QtProjects/build-qrcode-qt-unknown-Debug/image/result%1.png").arg(i));
    }

    //3.评估得分
    std::vector<int> scores = EvaluationMaskedImg(resultImgs);
    StringUtils::PRINT("评估得分：", scores);

    //4.选择最佳掩模图形
    maskNum = SelectBestMaskPattern(scores);

    finalImage = resultImgs.at(maskNum);
}

void Masking::RemoveMask(QImage &image)
{
    image = MaskedConvert(image, maskNum);
    image.save("removemask.png");
}


//std::vector<QImage> Masking::MaskPatterns()
//{
//    std::vector<QImage> vec;
//    for(int i = 0; i < 8; i++){
//        vec.push_back(GenerateMaskPattern(nMods, i));
//    }
//    return vec;
//}

//QImage Masking::GenerateMaskPattern(int mods, int num)
//{
//    QImage img(mods, mods, QImage::Format_RGB32);
//    img.fill(value_w);

//    for(int i = 0; i < mods; i++){
//        for(int j = 0; j < mods; j++){
//            if(!IsLocked(i, j)){
//                if(IsDarkModule(i, j, num)){
//                    img.setPixelColor(i, j, value_b);
//                }
//            }
//        }
//    }

//    img.save(QString("mask%1.png").arg(num));
//    return img;
//}

//bool Masking::IsDarkModule(int &x, int &y, int &num)
//{
//    switch (num) {
//    case 0:
//        if(Mask0(x, y)){
//            return true;
//        } else {
//            return false;
//        }
//        break;
//    case 1:
//        if(Mask1(x, y)){
//            return true;
//        } else {
//            return false;
//        }
//        break;
//    case 2:
//        if(Mask2(x, y)){
//            return true;
//        } else {
//            return false;
//        }
//        break;
//    case 3:
//        if(Mask3(x, y)){
//            return true;
//        } else {
//            return false;
//        }
//        break;
//    case 4:
//        if(Mask4(x, y)){
//            return true;
//        } else {
//            return false;
//        }
//        break;
//    case 5:
//        if(Mask5(x, y)){
//            return true;
//        } else {
//            return false;
//        }
//        break;
//    case 6:
//        if(Mask6(x, y)){
//            return true;
//        } else {
//            return false;
//        }
//        break;
//    case 7:
//        if(Mask7(x, y)){
//            return true;
//        } else {
//            return false;
//        }
//        break;
//    default:
//        return false;
//        break;
//    }
//    return false;
//}

bool Masking::IsLocked(int &x, int &y)
{
    //功能模块
    if(x >= 0 && x <= 7 && y >= 0 && y <= 7){
        return true;
    }
    if(x >= 0 && x <= 7 && y >= (nMods-8) && y <= (nMods-1)){
        return true;
    }
    if(x >= (nMods-8) && x <= (nMods-1) && y >= 0 && y <= 7){
        return true;
    }


    //定位图形、矫正图形、格式信息、版本信息模块
    auto result = std::find(lockModule.begin(), lockModule.end(),
                            std::make_pair(x, y));
    if(result != lockModule.end()){
        return true;
    }

    return false;
}

std::vector<QImage> Masking::MaskedImg()
{
    std::vector<QImage> imgs;
    for(int i = 0; i < 8; i++){
        //qDebug() << "第" << i << "个结果";
        imgs.push_back(MaskedConvert(initImage, i));
    }

    return imgs;
}

QImage Masking::MaskedConvert(QImage image, int n)
{
    for(int i = 0; i < nMods; i++){
        for(int j = 0; j < nMods; j++){
            if(!IsLocked(i, j)){
                if(WhetherToggle(i, j, n)){
                    ConvertColor(image, i, j);
                }
            }
        }
    }
    return image;
}

bool Masking::WhetherToggle(int &x, int &y, int &n)
{
    switch (n) {
    case 0:
        if(Mask0(x, y)){
            return true;
        } else {
            return false;
        }
        break;
    case 1:
        if(Mask1(x, y)){
            return true;
        } else {
            return false;
        }
        break;
    case 2:
        if(Mask2(x, y)){
            return true;
        } else {
            return false;
        }
        break;
    case 3:
        if(Mask3(x, y)){
            return true;
        } else {
            return false;
        }
        break;
    case 4:
        if(Mask4(x, y)){
            return true;
        } else {
            return false;
        }
        break;
    case 5:
        if(Mask5(x, y)){
            return true;
        } else {
            return false;
        }
        break;
    case 6:
        if(Mask6(x, y)){
            return true;
        } else {
            return false;
        }
        break;
    case 7:
        if(Mask7(x, y)){
            return true;
        } else {
            return false;
        }
        break;
    default:
        return false;
        break;
    }
    return false;
}

void Masking::ConvertColor(QImage &image, int &x, int &y)
{
    if(image.pixelColor(x, y) == value_b){
        image.setPixelColor(x, y, value_w);
    } else if(image.pixelColor(x, y) == value_w){
        image.setPixelColor(x, y, value_b);
    } else {
        qDebug() << "masking.cpp ConvertColor() 颜色转换失败";
    }
}

//std::vector<QImage> Masking::MaskedImg(std::vector<QImage> maskPatterns)
//{
//    qDebug() << "MaskedImg";
//    std::vector<QImage> imgs;
//    for(int i = 0; i < maskPatterns.size(); i++){
//        qDebug() << "第" << i << "个结果";
//        imgs.push_back(XORImgPattern(initImage, maskPatterns.at(i)));
//    }

//    return imgs;
//}

//QImage Masking::XORImgPattern(QImage img, QImage pattern)
//{
//    for(int i = 0; i < nMods; i++){
//        for(int j = 0; j < nMods; j++){
//            img.setPixelColor(i, j, XORColor(img.pixelColor(i, j),
//                                             pattern.pixelColor(i, j)));
//        }
//    }

//    return img;
//}

//QColor Masking::XORColor(QColor c1, QColor c2)
//{
//    if(c1 == c2){
//        return value_w;
//    } else if(c1 == value_y){
//        return value_y;
//    } else {
//        return value_b;
//    }

//}

std::vector<int> Masking::EvaluationMaskedImg(std::vector<QImage> maskedImg)
{
    std::vector<int> points;
    for(int i = 0; i < maskedImg.size(); i++){
        points.push_back(EvaluationPoints(maskedImg.at(i)));
    }

    return points;
}

int Masking::EvaluationPoints(QImage &image)
{
    return EvaluationCondition1(image) + EvaluationCondition2(image)
            + EvaluationCondition3(image) + EvaluationCondition4(image);
}

/**
 * @brief Masking::EvaluationCondition1 评估条件1
 * @param image
 * @return
 * Evaluation Condition #1
 * 特征：
 *   行/列中相邻的模块的颜色相同
 * 条件：
 *   模块数 = (5 + i)
 * 分数：
 *   3+i
 */
int Masking::EvaluationCondition1(QImage &image)
{
    int score_col = 0;
    int score_row = 0;
    QColor color_col;
    QColor color_row;
    int flag_col;
    int flag_row;
    //计算行列的分数
    for(int i = 0; i < nMods; i++){
        color_col = image.pixelColor(0, i);
        color_row = image.pixelColor(i, 0);
        flag_col = 1;
        flag_row = 1;
        for(int j = 0; j < nMods; j++){
            //每列的值
            if(IsSameColor(color_col, image.pixelColor(i, j))){
                flag_col++;
            } else {
                if(flag_col >= 5){
                    score_col = score_col + 3 + flag_col - 5;
                    color_col = image.pixelColor(i, j);
                    flag_col = 1;
                } else {
                    color_col = image.pixelColor(i, j);
                    flag_col = 1;
                }
            }
            //每行的值
            if(IsSameColor(color_row, image.pixelColor(j, i))){
                flag_row++;
            } else {
                if(flag_row >= 5){
                    score_row = score_row + 3 + flag_row - 5;
                    color_row = image.pixelColor(j, i);
                    flag_row = 1;
                } else {
                    color_row = image.pixelColor(j, i);
                    flag_row = 1;
                }
            }
        }
        if(flag_col >= 5){
            score_col = score_col + 3 + flag_col - 5;
        }
        if(flag_row >= 5){
            score_row = score_row + 3 + flag_row - 5;
        }
    }

    return score_col+score_row;
}

/**
 * @brief Masking::EvaluationCondition2 评估条件2
 * @param image
 * @return 分数
 * Evaluation Condition #2
 * 特征：
 *   颜色相同模块组成的块
 * 条件：
 *   模块数 = m * n
 * 分数：
 *   3 * (m-1) * (n -1)
 */
int Masking::EvaluationCondition2(QImage &image)
{
    int score = 0;

    for(int i = 0; i < nMods; i++){
        for(int j = 0; j < nMods; j++){
            if(i+1 < nMods && j+1 < nMods){
                if(IsSameColor(image.pixelColor(i, j), image.pixelColor(i+1, j),
                               image.pixelColor(i, j+1), image.pixelColor(i+1, j+1))){
                    score += 3;
                }
            }
        }
    }

    return score;
}

/**
 * @brief Masking::EvaluationCondition3 评估条件3
 * @param image
 * @return
 * Evaluation Condition #3
 * 特征：
 *   在行/列中出现1:1:3:1:1(深浅深浅深)图形，并在其前或后有4个白色模块
 * 条件：
 *
 * 分数：
 *   40
 */
int Masking::EvaluationCondition3(QImage &image)
{
    int score = 0;
    for(int i = 0; i < nMods; i++){
        for(int j = 0; j < nMods; j++){
            //列方向
            if(IsModule11311(image, i, j, DIR_COL)){
                if(j+10 < nMods){
                    if(IsSameColor(value_w, image.pixelColor(i, j+7), image.pixelColor(i, j+8),
                                   image.pixelColor(i, j+9), image.pixelColor(i, j+10))){
                        score += 40;
                    }
                }
                if(j-4 >= 0){
                    if(IsSameColor(value_w, image.pixelColor(i, j-1), image.pixelColor(i, j-2),
                                   image.pixelColor(i, j-3), image.pixelColor(i, j-4))){
                        score += 40;
                    }
                }
            }
            //行方向
            if(IsModule11311(image, i, j, DIR_ROW)){
                if(i+10 < nMods){
                    if(IsSameColor(value_w, image.pixelColor(i+7, j), image.pixelColor(i+8, j),
                                   image.pixelColor(i+9, j), image.pixelColor(i+10, j))){
                        score += 40;
                    }
                }
                if(i-4 >= 0){
                    if(IsSameColor(value_w, image.pixelColor(i-1, j), image.pixelColor(i-2, j),
                                   image.pixelColor(i-3, j), image.pixelColor(i-4, j))){
                        score += 40;
                    }
                }
            }
        }
    }

    return score;
}

/**
 * @brief Masking::EvaluationCondition4 评估条件4
 * @param image
 * @return
 * Evaluation Condition #4
 * 特征：
 *   整个符号中深色模块的比率
 * 条件：
 *   50+-(5*k)%到50+-(5*(k+1))%
 * 分数：
 *   10k
 */
int Masking::EvaluationCondition4(QImage &image)
{
    int darkmodules = 0;
    int totalmoduels = nMods*nMods;

    for(int i = 0; i < nMods; i++){
        for(int j = 0; j < nMods; j++){
            if(IsSameColor(image.pixelColor(i, j), value_b)){
                darkmodules++;
            }
        }
    }

    int percent = (darkmodules*100) / totalmoduels;
    int prePercent = percent - percent%5;
    int nextPercent = prePercent + 5;
    int k1 = abs(prePercent-50) / 5;
    int k2 = abs(nextPercent-50) / 5;
    int k = k1<k2?k1:k2;

    return k*10;
}

/**
 * @brief Masking::IsModule11311 是否符合1:1:3:1:1格式
 * @param image
 * @param x
 * @param y
 * @param direction 延伸方向
 * @return
 *   判断从(x, y)处开始的模块是否符合(dark:light:dark:dark:dark:light:dark)
 */
bool Masking::IsModule11311(QImage &image, int x, int y, int direction)
{
    switch (direction) {
    case 1:
        if(x+6 < nMods){
            if(IsSameColor(image.pixelColor(x, y), value_b)
                    && IsSameColor(image.pixelColor(x+1, y), value_w)
                    && IsSameColor(image.pixelColor(x+2, y), value_b)
                    && IsSameColor(image.pixelColor(x+3, y), value_b)
                    && IsSameColor(image.pixelColor(x+4, y), value_b)
                    && IsSameColor(image.pixelColor(x+5, y), value_w)
                    && IsSameColor(image.pixelColor(x+6, y), value_b)){
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
        break;
    case 0:
        if(y+6 < nMods){
            if(IsSameColor(image.pixelColor(x, y), value_b)
                    && IsSameColor(image.pixelColor(x, y+1), value_w)
                    && IsSameColor(image.pixelColor(x, y+2), value_b)
                    && IsSameColor(image.pixelColor(x, y+3), value_b)
                    && IsSameColor(image.pixelColor(x, y+4), value_b)
                    && IsSameColor(image.pixelColor(x, y+5), value_w)
                    && IsSameColor(image.pixelColor(x, y+6), value_b)){
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
        break;
    default:
        break;
    }
}

bool Masking::IsDark(QColor color)
{
    if(color == value_b){
        return true;
    } else {
        return false;
    }
}

bool Masking::IsSameColor(QColor c1, QColor c2)
{
    if(c1 == c2){
        return true;
    } else if((c1 != value_b) && (c2 != value_b)){
        return true;
    } else {
        return false;
    }
}

bool Masking::IsSameColor(QColor c1, QColor c2, QColor c3, QColor c4)
{
    if((c1 == c2) && (c2 == c3) && (c3 == c4)){
        return true;
    } else {
        return false;
    }
}

bool Masking::IsSameColor(QColor c1, QColor c2, QColor c3, QColor c4, QColor c5)
{
    if(IsSameColor(c1, c2, c3, c4)){
        if(c5 == c4){
            return true;
        } else {
            return false;
        }
    } else {
        return false;
    }
}

int Masking::SelectBestMaskPattern(std::vector<int> &scores)
{
    int pattern = 0;
    int score = scores.at(0);
    for(int i = 1; i < scores.size(); i++){
        if(score > scores.at(i)){
            score = scores.at(i);
            pattern = i;
        }
    }
    return pattern;
}

bool Masking::Mask0(int &x, int &y)
{
    if((x + y) % 2){
        return false;
    } else {
        return true;
    }
}

bool Masking::Mask1(int &x, int &y)
{
    if(y % 2){
        return false;
    } else {
        return true;
    }
}

bool Masking::Mask2(int &x, int &y)
{
    if(x % 3){
        return false;
    } else {
        return true;
    }
}

bool Masking::Mask3(int &x, int &y)
{
    if((x + y) % 3){
        return false;
    } else {
        return true;
    }
}

bool Masking::Mask4(int &x, int &y)
{
    if((int)(floor(y / 2) + floor(x / 3)) % 2){
        return false;
    } else {
        return true;
    }
}

bool Masking::Mask5(int &x, int &y)
{
    if(((x * y) % 2) + ((x * y) %3)){
        return false;
    } else {
        return true;
    }
}

bool Masking::Mask6(int &x, int &y)
{
    if((((x * y) % 2) + ((x * y) % 3)) % 2){
        return false;
    } else {
        return true;
    }
}

bool Masking::Mask7(int &x, int &y)
{
    if((((x + y) % 2) + ((x * y) % 3)) % 2){
        return false;
    } else {
        return true;
    }
}

void Masking::setLockModule(const std::vector<std::pair<int, int> > &value)
{
    lockModule = value;
}

int Masking::getMaskNum() const
{
    return maskNum;
}

void Masking::setMaskNum(int value)
{
    maskNum = value;
}

void Masking::setInitImage(const QImage &value)
{
    initImage = value;
}

QImage Masking::getFinalImage() const
{
    return finalImage;
}


}
